package com.atguigu.spzx.manager.filter;

import com.alibaba.fastjson.JSON;
import com.atguigu.spzx.common.constant.SysUserStatusEnum;
import com.atguigu.spzx.common.utils.IpUtil;
import com.atguigu.spzx.common.utils.JwtHelper;
import com.atguigu.spzx.common.utils.ResponseUtil;
import com.atguigu.spzx.common.result.Result;
import com.atguigu.spzx.common.result.ResultCodeEnum;
import com.atguigu.spzx.manager.custom.CustomUser;
import com.atguigu.spzx.manager.service.LoginLogService;
import com.atguigu.spzx.manager.vo.SysLoginReqVo;
import com.atguigu.spzx.manager.vo.SysLoginRespVo;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * <p>
 * TokenLoginFilter
 * </p>
 *
 * @author flyduck
 * @since 2023/10/26
 */
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

    private RedisTemplate redisTemplate;

    private LoginLogService loginLogService;

    //构造器
    public TokenLoginFilter(AuthenticationManager authenticationManager, RedisTemplate redisTemplate, LoginLogService loginLogService) {
        this.setAuthenticationManager(authenticationManager);
        this.setPostOnly(false);
        //指定登录接口及提交方式，可以指定任意路径
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/system/index/login","POST"));
        this.redisTemplate = redisTemplate;
        this.loginLogService = loginLogService;
    }

    //获取登录名密码，进行认证
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            SysLoginReqVo loginReqVo = new ObjectMapper().readValue(request.getInputStream(), SysLoginReqVo.class);
            Authentication authentication = new UsernamePasswordAuthenticationToken(loginReqVo.getUsername(),loginReqVo.getPassword());
            return this.getAuthenticationManager().authenticate(authentication);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    //认证成功会调用
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {
        //获取认证对象
        CustomUser customUser = (CustomUser) authentication.getPrincipal();

        //生成token
        String token = JwtHelper.createToken(customUser.getSysUser().getId(), customUser.getSysUser().getUsername());

        //认证成功保存权限到redis
        redisTemplate.opsForValue().set(customUser.getUsername(), JSON.toJSONString(customUser.getAuthorities()));

        //记录登录日志
        loginLogService.recordLoginLog(customUser.getUsername(), SysUserStatusEnum.NORMAL.getCode(), IpUtil.getIpAddress(request),"登录成功");

        //返回
        SysLoginRespVo respVo = new SysLoginRespVo();
        respVo.setToken(token);
        ResponseUtil.out(response, Result.ok(respVo));
    }

    //认证失败会调用
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
        if(e.getCause() instanceof RuntimeException) {
            ResponseUtil.out(response, Result.fail(ResultCodeEnum.DATA_ERROR, e.getMessage()));
        } else {
            ResponseUtil.out(response, Result.fail(ResultCodeEnum.ACCOUNT_ERROR));
        }
    }
}
